/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 metatile_texture.h

	$Header: /heroes4/metatile_texture.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( METATILE_TEXTURE_H_INCLUDED )
#define METATTILE_TEXTURE_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <cassert>
#include <vector>
#include "adventure_tile_size.h"
#include "elements_of.h"
#include "map_point.h"
#include "pixel_24.h"
#include "resource_traits.h"
#include "shared_ptr.h"
#include "sized_int_types.h"
#include "uncopyable.h"

/////////////////////////////////////////////////////////////////////////////

int const k_metatile_logical_size = 4;
int const k_metatile_texture_full_size = 10;
int const k_metatile_texture_core_size = 6;
int const k_metatile_texture_border_size = ( k_metatile_texture_full_size - k_metatile_texture_core_size ) / 2;
int const k_metatile_max_offset = k_metatile_texture_core_size - k_metatile_logical_size;

int const k_metatile_texture_screen_width = k_adventure_tile_width * k_metatile_texture_full_size;
int const k_metatile_texture_screen_height = k_adventure_tile_height * k_metatile_texture_full_size;
t_screen_point const k_metatile_texture_screen_size( k_metatile_texture_screen_width, k_metatile_texture_screen_height );

/////////////////////////////////////////////////////////////////////////////
// t_adventure_tile_texture class

class t_adventure_tile_texture
{
public:
	// Constructors
	t_adventure_tile_texture() {}
	t_adventure_tile_texture( std::vector< t_uint8 > & data, int const ( & new_column_offset_array )[ k_adventure_tile_width ] );

	// Member functions
	t_uint8 const * get_column_ptr( int column ) const;
	
	bool read( std::streambuf & buffer );
	void set_data( std::vector< t_uint8 > & new_data, int const ( & new_column_offset_array )[ k_adventure_tile_width ] );
	bool write( std::streambuf & buffer ) const;

private:
	// Data members
	int						m_column_offset_array[ k_adventure_tile_width ];
	std::vector< t_uint8 >	m_data;
};

inline t_uint8 const * t_adventure_tile_texture::get_column_ptr( int column ) const
{
	assert( column >= 0 && column < k_adventure_tile_width );
	return &m_data[ m_column_offset_array[ column ] ];
}

/////////////////////////////////////////////////////////////////////////////
// base class for terrain textures
/////////////////////////////////////////////////////////////////////////////
class t_metatile_texture_base : private t_uncopyable
{
public:
	// Member functions
	t_adventure_tile_texture& get_adventure_tile_texture( t_map_point_2d const & pos );
	t_adventure_tile_texture const & get_adventure_tile_texture( t_map_point_2d const & pos ) const;

protected:
	t_metatile_texture_base();
	void copy_data( t_metatile_texture_base const& source );

	// Data members
	t_adventure_tile_texture m_tile_texture_arr[ k_metatile_texture_full_size 
		                                         * k_metatile_texture_full_size ];
};

/////////////////////////////////////////////////////////////////////////////
// inlines
/////////////////////////////////////////////////////////////////////////////
inline t_metatile_texture_base::t_metatile_texture_base()
{
}

inline void t_metatile_texture_base::copy_data( t_metatile_texture_base const& source )
{
	int i;

	for (i = 0; i < ELEMENTS_OF(m_tile_texture_arr); i++)
		m_tile_texture_arr[i] = source.m_tile_texture_arr[i];
}

inline t_adventure_tile_texture& t_metatile_texture_base::get_adventure_tile_texture( t_map_point_2d const & pos )
{
	assert( pos.row >= 0 && pos.row < k_metatile_texture_full_size );
	assert( pos.column >= 0 && pos.column < k_metatile_texture_full_size );

	return m_tile_texture_arr[ pos.column * k_metatile_texture_full_size + pos.row ];
}

inline t_adventure_tile_texture const & t_metatile_texture_base::get_adventure_tile_texture( t_map_point_2d const & pos ) const
{
	assert( pos.row >= 0 && pos.row < k_metatile_texture_full_size );
	assert( pos.column >= 0 && pos.column < k_metatile_texture_full_size );

	return m_tile_texture_arr[ pos.column * k_metatile_texture_full_size + pos.row ];
}

/////////////////////////////////////////////////////////////////////////////
// t_metatile_texture24 class - 24 bit paletted terrain tile
/////////////////////////////////////////////////////////////////////////////
class t_metatile_texture_24 : public t_metatile_texture_base
{
public:
	std::vector<t_pixel_24> const& get_palette() const;

	bool read( std::streambuf& buffer );
	void set_palette( std::vector<t_pixel_24> const& palette );
	bool write( std::streambuf& buffer ) const;

private:
	std::vector< t_pixel_24 >  m_palette;
};

inline std::vector< t_pixel_24 > const& t_metatile_texture_24::get_palette() const
{
	return m_palette;
}

inline void t_metatile_texture_24::set_palette( std::vector<t_pixel_24> const& palette )
{
	m_palette = palette;
}

inline bool read( std::streambuf & stream, t_metatile_texture_24 & texture )
{
	return texture.read( stream );
}

/////////////////////////////////////////////////////////////////////////////
// t_metatile_texture class - 16 bit paletted terrain tile
/////////////////////////////////////////////////////////////////////////////

class t_metatile_texture : public t_metatile_texture_base
{
public:
	// Constructor
	t_metatile_texture( t_metatile_texture_24 const & src_tile );

	t_uint16 const* get_palette() const;

private:
	std::vector< t_uint16 > m_palette;
};

inline t_uint16 const* t_metatile_texture::get_palette() const
{
	return &(*m_palette.begin());
}

template <>
struct t_resource_traits<t_metatile_texture_24>
{
	static char const prefix[];
	static char const extension[];
};


#endif // !defined( METATILE_TEXTURE_H_INCLUDED )
